home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
dbg
/
ds3100.md
/
dbgMain.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
32KB
|
1,248 lines
/* dbgMain.c -
*
* This contains the routines which read and execute commands from kdbx.
*
* Copyright (C) 1989 Digital Equipment Corporation.
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies.
* Digital Equipment Corporation makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dbg/ds3100.md/dbgMain.c,v 9.13 92/09/29 15:52:12 jhh Exp $ SPRITE (Berkeley)";
#endif not lint
#include <sprite.h>
#include <dbg.h>
#include <dbgInt.h>
#include <mach.h>
#include <machConst.h>
#include <proc.h>
#include <vm.h>
#include <vmMach.h>
#include <machMon.h>
#include <net.h>
#include <netEther.h>
#include <netInet.h>
#include <dev.h>
#include <sys.h>
#include <sync.h>
#include <main.h>
#ifdef KDBX
#include <user/signal.h>
#endif
extern Address vmStackBaseAddr;
extern Address vmStackEndAddr;
extern Address vmBlockCacheBaseAddr;
extern Address vmBlockCacheEndAddr;
extern Address vmBootEnd;
static unsigned sstepInst; /* The instruction that was
* replaced when we tried to
* single step. */
Boolean dbg_InDebugger = FALSE; /* TRUE if are currently in
* the debug command loop. */
Boolean dbg_BeingDebugged = FALSE; /* TRUE if are under control
* of kdbx.*/
Boolean dbg_Rs232Debug = FALSE; /* TRUE if are using the RS232
* line to debug, FALSE if are
* using the network. */
Boolean dbg_UsingNetwork = FALSE; /* TRUE if the debugger is
* using the network interface*/
static char requestBuffer[DBG_MAX_REQUEST_SIZE];/* Buffer to receive request
* into. */
static int requestOffset; /* Offset in buffer where next
* bytes should be read from.*/
static char replyBuffer[DBG_MAX_REPLY_SIZE + 2];/* Buffer to hold reply. */
static int replyOffset = 0; /* Offset in buffer where next
* bytes in reply should go. */
static unsigned int curMsgNum; /* The current message that
* is being processed. */
int dbgTraceLevel = 0; /* The debugger tracing
* level. */
/*
* Number of times to poll before timing out and resending (about 2 seconds).
*/
int dbgTimeout = 15000;
/*
* Information about the latest packet received.
*/
Boolean dbgGotPacket;
int dbgPacketLength;
Net_InetAddress dbgMyIPAddr;
Net_InetAddress dbgSrcIPAddr;
Net_InetAddress dbgSrcPort;
Net_EtherHdr dbgEtherHdr;
Net_ScatterGather dbgGather;
Net_Interface *dbgInterPtr = (Net_Interface *) NIL;
/*
* Size of debugging packet header and data.
*/
#define PACKET_HDR_SIZE (sizeof(Net_EtherHdr) + Dbg_PacketHdrSize() + 4 + 2)
#define PACKET_DATA_SIZE (DBG_MAX_REPLY_SIZE - PACKET_HDR_SIZE)
/*
* Strings which describe each of the opcodes that kdbx can send us.
*/
static char *opcodeNames[] = DBG_OPCODE_NAMES ;
/*
* Strings which describe the different exceptions that can occur.
*/
static char *exceptionNames[] = DBG_EXCEPTION_NAMES;
/*
* Whether syslog should remain diverted on continue or not.
*/
static Boolean syslogDiverted = FALSE;
/*
* Declare global variables.
*/
int dbgTermReason;
int dbgInDebugger;
int dbgIntPending;
Boolean dbgPanic;
Boolean dbg_UsingSyslog = FALSE;
Boolean dbgCanUseSyslog = TRUE;
int dbgMaxStackAddr;
#ifdef KDBX
int dbgSignal;
static Boolean useKdbx = FALSE;
#endif
/*
* Trap causes (same numbering as in ptrace.h).
*/
#define CAUSE_SINGLE 4
#define CAUSE_BREAK 5
/*
* Trap instruction.
*/
#define SSTEP_INST (MACH_SSTEP_VAL | 0xd)
/*
* Forward declarations:
*/
static char * TranslateOpcode _ARGS_((int opcode));
static char * TranslateException _ARGS_((int exception));
static Boolean ReadRequest _ARGS_((Boolean timeout));
static void SendReply _ARGS_((int dataSize));
static void DebugToRegState _ARGS_((Mach_DebugState *debugPtr,
Mach_RegState *regPtr));
static void RegStateToDebug _ARGS_((Mach_RegState *regPtr,
Mach_DebugState *debugPtr));
#ifdef KDBX
static int sigMap[] = {
/* MACH_EXC_INT */ SIGILL,
/* MACH_EXC_TLB_MOD */ SIGSEGV,
/* MACH_EXC_TLB_LD_MISS */ SIGSEGV,
/* MACH_EXC_TLB_ST_MISS */ SIGSEGV,
/* MACH_EXC_ADDR_ERR_LD */ SIGBUS,
/* MACH_EXC_ADDR_ERR_ST */ SIGBUS,
/* MACH_EXC_BUS_ERR_IFETCH */ SIGBUS,
/* MACH_EXC_BUS_ERR_LD_ST */ SIGBUS,
/* MACH_EXC_SYSCALL */ SIGSYS,
/* MACH_EXC_BREAK */ SIGTRAP,
/* MACH_EXC_RES_INST */ SIGILL,
/* MACH_EXC_COP_UNUSABLE */ SIGILL,
/* MACH_EXC_OVFLOW */ SIGILL,
};
#endif
/*
* ----------------------------------------------------------------------------
*
* Dbg_InRange --
*
* Return true if the given address is a valid kernel address and false
* otherwise.
*
* Results:
* True if the given address is a valid kernel address and false
* otherwise.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
Boolean Dbg_InRange(addr, numBytes, writeable)
unsigned int addr; /* Beginning address to check. */
int numBytes; /* Number of bytes to check. */
Boolean writeable; /* TRUE => address must be writeable. */
{
int firstPage;
int lastPage;
firstPage = addr >> VMMACH_PAGE_SHIFT;
lastPage = (addr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
if (firstPage != lastPage) {
Mach_MonPrintf("Dbg_InRange: Object spans pages\n");
return(FALSE);
}
return(VmMach_MakeDebugAccessible(addr));
}
/*
* ----------------------------------------------------------------------------
*
* TranslateOpcode --
*
* Return the string which describes the given opcode.
*
* Results:
* Pointer to the string which describes the given opcode.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
static char *
TranslateOpcode(opcode)
int opcode; /* The opcode which is to be translated. */
{
int index;
index = (int) opcode;
if (index < 0 || index >= sizeof(opcodeNames) / 4) {
index = 0;
}
return(opcodeNames[index]);
}
/*
* ----------------------------------------------------------------------------
*
* TranslateException --
*
* Return the string that describes the given exception.
*
* Results:
* Pointer to string which describes the given exception.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
static char *
TranslateException(exception)
int exception; /* The exception which is to be translated. */
{
if (exception < 0 || exception > MACH_EXC_OVFLOW) {
return("Unknown");
} else {
return(exceptionNames[exception]);
}
}
/*
* ----------------------------------------------------------------------------
*
* Dbg_Init --
*
* Initialize the debugger.
*
* Results:
* None.
*
* Side effects:
* Global variables are initialized.
*
* ----------------------------------------------------------------------------
*/
void
Dbg_Init()
{
#ifdef KDBX
extern void DbgDbxInit();
#endif
dbgInDebugger = 0;
dbgIntPending = 0;
dbgPanic = FALSE;
dbg_BeingDebugged = FALSE;
#ifdef KDBX
DbgDbxInit();
#endif
}
/*
* ----------------------------------------------------------------------------
*
* Dbg_InputPacket --
*
* See if the current packet is for us.
*
* Results:
* None.
*
* Side effects:
* dbgGotPacket is set to true if we got a packet that we liked.
*
* ----------------------------------------------------------------------------
*/
void
Dbg_InputPacket(interPtr, packetPtr, packetLength)
Net_Interface *interPtr;
Address packetPtr;
int packetLength;
{
Net_EtherHdr *etherHdrPtr;
Net_IPHeader *ipPtr;
Address dataPtr;
int dataLength;
if (interPtr->netType != NET_NETWORK_ETHER) {
return;
}
etherHdrPtr = (Net_EtherHdr *)packetPtr;
if (dbgTraceLevel >= 5) {
if ((unsigned char)etherHdrPtr->destination.byte1 != 0xff) {
Mach_MonPrintf("Size=%d S: %x:%x:%x:%x:%x:%x D: %x:%x:%x:%x:%x:%x T=%x\n",
packetLength,
(unsigned char)etherHdrPtr->source.byte1,
(unsigned char)etherHdrPtr->source.byte2,
(unsigned char)etherHdrPtr->source.byte3,
(unsigned char)etherHdrPtr->source.byte4,
(unsigned char)etherHdrPtr->source.byte5,
(unsigned char)etherHdrPtr->source.byte6,
(unsigned char)etherHdrPtr->destination.byte1,
(unsigned char)etherHdrPtr->destination.byte2,
(unsigned char)etherHdrPtr->destination.byte3,
(unsigned char)etherHdrPtr->destination.byte4,
(unsigned char)etherHdrPtr->destination.byte5,
(unsigned char)etherHdrPtr->destination.byte6,
Net_NetToHostShort(etherHdrPtr->type));
}
}
if (Net_NetToHostShort(etherHdrPtr->type) != NET_ETHER_IP) {
if (dbgTraceLevel >= 5) {
Mach_MonPrintf("Non-IP (Type=0x%x) ",
Net_NetToHostShort(etherHdrPtr->type));
}
return;
}
if (dbgGotPacket) {
if (dbgTraceLevel >= 4) {
Mach_MonPrintf("Dbg_InputPacket: already have a packet\n");
}
return;
}
if (dbgTraceLevel >= 4) {
Mach_MonPrintf("Validating packet\n");
}
{
static char alignedBuffer[NET_ETHER_MAX_BYTES];
/*
* Make sure the packet starts on a 32-bit boundry so that we can
* use structures for describe the data.
*/
if ( (unsigned int) (packetPtr + sizeof(Net_EtherHdr)) & 0x3 ) {
bcopy (packetPtr + sizeof(Net_EtherHdr), alignedBuffer,
packetLength - sizeof(Net_EtherHdr));
packetPtr = alignedBuffer;
} else {
packetPtr = packetPtr + sizeof(Net_EtherHdr);
}
if (Dbg_ValidatePacket(packetLength - sizeof(Net_EtherHdr),
(Net_IPHeader *)(packetPtr),
&dataLength, &dataPtr,
&dbgMyIPAddr, &dbgSrcIPAddr, &dbgSrcPort)) {
if (dbgTraceLevel >= 4) {
Mach_MonPrintf("Got a packet: length=%d\n", dataLength);
}
bcopy((Address)etherHdrPtr, (Address)&dbgEtherHdr,
sizeof(Net_EtherHdr));
dbgGotPacket = TRUE;
bcopy(dataPtr, requestBuffer, dataLength);
#ifdef KDBX
DbgDbxStoreRequest(dataLength, requestBuffer);
#endif
/*
* Set the interface we are using.
*/
dbgInterPtr = interPtr;
return;
}
}
}
/*
* ----------------------------------------------------------------------------
*
* ReadRequest --
*
* Read the next request from kdbx.
*
* Results:
* None.
*
* Side effects:
* TRUE if didn't time out.
*
* ----------------------------------------------------------------------------
*/
static Boolean
ReadRequest(timeout)
Boolean timeout; /* TRUE if should timeout after waiting a
* while. */
{
int timeOutCounter;
Net_Interface *interPtr;
int i;
dbgGotPacket = FALSE;
timeOutCounter = dbgTimeout;
do {
/*
* Listen on all the interfaces. The debugger is relatively
* stateless so its easiest to just listen on them all.
*/
for (i = 0; ; i++) {
interPtr = Net_NextInterface(TRUE, &i);
if (interPtr == (Net_Interface *) NIL) {
break;
}
Net_RecvPoll(interPtr);
if (dbgGotPacket) {
break;
}
}
if (timeout) {
timeOutCounter--;
}
} while(!dbgGotPacket && timeOutCounter != 0);
if (dbgGotPacket) {
replyOffset = PACKET_HDR_SIZE;
requestOffset = 4;
curMsgNum = *(unsigned int *)(requestBuffer);
#ifdef KDBX
if (curMsgNum > 0x40000000) {
useKdbx = FALSE;
} else {
useKdbx = TRUE;
}
#endif
if (dbgTraceLevel >= 4) {
Mach_MonPrintf("MsgNum = %d\n", curMsgNum);
}
}
return(dbgGotPacket);
}
/*
* ----------------------------------------------------------------------------
*
* GetRequestBytes --
*
* Get the next numBytes bytes from the current request.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
static void
GetRequestBytes(numBytes, dest)
int numBytes;
Address dest;
{
bcopy(requestBuffer + requestOffset, dest, numBytes);
requestOffset += numBytes;
}
/*
* ----------------------------------------------------------------------------
*
* PutReplyBytes --
*
* Put the given bytes into the reply buffer.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
static void
PutReplyBytes(numBytes, src)
int numBytes;
Address src;
{
if (replyOffset + numBytes > DBG_MAX_REPLY_SIZE) {
Mach_MonPrintf("PutReplyBytes: Buffer overflow\n");
numBytes = DBG_MAX_REPLY_SIZE - replyOffset;
}
bcopy(src, &replyBuffer[replyOffset], numBytes);
replyOffset += numBytes;
}
/*
* ----------------------------------------------------------------------------
*
* SendReply --
*
* Send a reply to kdbx.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
static void
SendReply(dataSize)
int dataSize;
{
Net_EtherHdr *etherHdrPtr;
if (dbgTraceLevel >= 4) {
Mach_MonPrintf("Sending reply\n");
}
etherHdrPtr = (Net_EtherHdr *) (replyBuffer+2);
etherHdrPtr->source = dbgEtherHdr.destination;
etherHdrPtr->destination = dbgEtherHdr.source;
etherHdrPtr->type = dbgEtherHdr.type;
dbgGather.bufAddr = replyBuffer + sizeof(Net_EtherHdr)+2;
dbgGather.length = replyOffset - sizeof(Net_EtherHdr)-2;
dbgGather.mutexPtr = (Sync_Semaphore *) NIL;
bcopy((char *)&curMsgNum,(char *)(replyBuffer + PACKET_HDR_SIZE - 4),4);
Dbg_FormatPacket(dbgMyIPAddr, dbgSrcIPAddr, dbgSrcPort,
replyOffset - sizeof(Net_EtherHdr) - Dbg_PacketHdrSize()-2,
replyBuffer + sizeof(Net_EtherHdr) + 2);
Net_RawOutput(dbgInterPtr, etherHdrPtr, &dbgGather, 1);
if (dbgTraceLevel >= 4) {
Mach_MonPrintf("Sent reply\n");
}
}
/*
* Should we sync the disks on entering the debugger?
*/
Boolean dbgSyncDisks = TRUE;
extern Mach_DebugState mach_DebugState;
/*
* Place where the TLB is dumped when the kernel enters the debugger.
*/
unsigned dbgTLB[VMMACH_NUM_TLB_ENTRIES][2];
static Mach_DebugState *debugStatePtr;
/*
* ----------------------------------------------------------------------------
*
* Dbg_Main --
*
* The main debugger loop. This will read commands from the network
* and call the proper routine to execute them.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
unsigned
Dbg_Main()
{
unsigned cause;
Boolean done; /* Boolean to tell us whether to leave
* the main debugger loop */
Dbg_Opcode opcode; /* The operation that was requested */
/* Process table entry that we switched
* stacks to. */
Proc_ControlBlock *procPtr = (Proc_ControlBlock *) NIL;
Boolean atInterruptLevel;/* TRUE if we were entered from an
* interrupt handler. */
extern int Mach_SwitchPoint();
#ifdef NOTDEF
/*
* This code causes machines to "pop out" of the debugger.
*/
if (!dbg_BeingDebugged && dbgSyncDisks) {
/*
* Try to sync the disks if we aren't at interrupt level. If we
* are don't bother because we'll just hang waiting for interrupts.
* Of course I could force interrupts to be enabled but I'm not sure
* if that's a great idea.
*/
if (mach_NumDisableIntrsPtr[0] == 0 &&
!mach_AtInterruptLevel) {
Mach_EnableIntr();
Sys_SyncDisks(MACH_OTHER_TRAP_TYPE);
Mach_DisableIntr();
}
}
#endif NOTDEF
dbg_InDebugger = TRUE;
debugStatePtr = &mach_DebugState;
if (dbgTraceLevel >= 1) {
unsigned int *sp;
extern int etext;
Mach_MonPrintf("\nCause=%x SR=%x excPC=%x SP=%x BVA=%x\n",
mach_DebugState.causeReg, mach_DebugState.statusReg,
mach_DebugState.excPC, mach_DebugState.regs[SP],
mach_DebugState.badVaddr);
Mach_MonPrintf("Stack:\n");
for (sp = (unsigned *)mach_DebugState.regs[SP];
sp < (unsigned *)0x80030000;
sp++) {
if ((*sp < (unsigned int)&etext) && (*sp >= (unsigned)0x80030000)) {
Mach_MonPrintf("%x\n", *sp);
}
}
}
atInterruptLevel = mach_AtInterruptLevel;
mach_AtInterruptLevel = TRUE;
/*
* Force system log output to the console.
*/
if (!syslogDiverted) {
Dev_SyslogDebug(TRUE);
}
/*
* We want to inform the user what caused the problem. However we only
* tell him if: 1) we are debugging the debugger; 2) we are not under
* debugger control (i.e. we don't want to inform the user on every trace
* trap), 3) we got something besides a trace trap or a breakpoint trap
* exception.
*/
cause = (mach_DebugState.causeReg & MACH_CR_EXC_CODE) >>
MACH_CR_EXC_CODE_SHIFT;
if (dbgPanic) {
dbgPanic = FALSE;
mach_DebugState.excPC = mach_DebugState.regs[RA];
}
if (dbgTraceLevel >= 1 || !dbg_BeingDebugged ||
cause != MACH_EXC_BREAK) {
(void)Dev_VidEnable(TRUE); /* unblank the screen */
printf("Entering debugger with a %s exception at PC 0x%x\r\n",
TranslateException((int)cause),
mach_DebugState.excPC);
}
#ifdef KDBX
if ((cause >= 0) && (cause < MACH_EXC_MAX)) {
dbgSignal = sigMap[cause];
} else {
dbgSignal = SIGILL;
}
#endif
if (cause == MACH_EXC_BREAK) {
unsigned *pc;
if (mach_DebugState.causeReg & MACH_CR_BR_DELAY) {
pc = (unsigned *)(mach_DebugState.excPC + 4);
} else {
pc = (unsigned *)mach_DebugState.excPC;
}
if (dbgTraceLevel >= 1) {
Mach_MonPrintf("break inst: %x\n", *pc);
}
if ((*pc & MACH_BREAK_CODE_FIELD) == MACH_SSTEP_VAL) {
if (dbgTraceLevel >= 1) {
Mach_MonPrintf("sstep\n");
}
mach_DebugState.trapCause = CAUSE_SINGLE;
if (dbgTraceLevel >= 1) {
Mach_MonPrintf("sstep (%x) = %x\n", pc, sstepInst);
}
Mach_FlushCode((Address)pc, 4);
*pc = sstepInst;
Mach_EmptyWriteBuffer();
} else {
mach_DebugState.trapCause = CAUSE_BREAK;
}
}
dbg_UsingNetwork = TRUE;
if (dbg_BeingDebugged) {
unsigned char ch;
int timeout = 5;
ch = 0;
#ifdef KDBX
if (useKdbx) {
Dbg_DbxMain();
goto there;
}
#endif
PutReplyBytes(1, (Address)&ch);
SendReply();
do {
if (ReadRequest(TRUE)) {
GetRequestBytes(4, (Address)&opcode);
if (opcode != DBG_CONTINUE) {
break;
} else {
PutReplyBytes(4, (Address) &opcode);
SendReply();
continue;
}
}
/*
* We can only timeout if we are using network debugging.
*/
Net_RawOutput(dbgInterPtr, (Address) replyBuffer,
&dbgGather, 1);
if (dbgTraceLevel >= 5) {
Mach_MonPrintf("DBG: Timeout\n");
}
Mach_MonPrintf("TI ");
} while (timeout-- > 0);
} else {
(void) ReadRequest(FALSE);
#ifdef KDBX
if (useKdbx) {
Dbg_DbxMain();
goto there;
}
#endif
GetRequestBytes(4, (Address)&opcode);
}
Vm_MachDumpTLB(dbgTLB);
done = FALSE;
while (!done) {
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("Request: (%d) %s\n", opcode, TranslateOpcode(opcode));
}
switch (opcode) {
/*
* The client wants to read some data from us ...
*/
case DBG_GET_STOP_INFO: {
StopInfo stopInfo;
stopInfo.codeStart = (int)mach_CodeStart;
if (procPtr != (Proc_ControlBlock *) NIL &&
procPtr->machStatePtr != (Mach_State *)NIL) {
stopInfo.regs = procPtr->machStatePtr->switchRegState;
/*
* The pc isn't stored in switchRegState, but we know
* that we had to be in Mach_ContextSwitch. Also,
* when the context switch is done the status register
* and a magic number are pushed on the stack. We
* need to adjust the sp so that the debugger doesn't
* get confused by them.
*/
stopInfo.regs.pc = (Address)
((int) Mach_ContextSwitch + 16);
stopInfo.regs.regs[SP] += 8;
} else {
DebugToRegState(&mach_DebugState, &stopInfo.regs);
}
stopInfo.trapType = cause;
PutReplyBytes(sizeof(stopInfo), (Address)&stopInfo);
SendReply();
break;
}
case DBG_READ_ALL_REGS: {
Mach_RegState regState;
if (procPtr != (Proc_ControlBlock *) NIL &&
procPtr->machStatePtr != (Mach_State *)NIL) {
regState = procPtr->machStatePtr->switchRegState;
regState.pc = (Address) (Mach_SwitchPoint);
regState.pc = (Address)
((int) Mach_ContextSwitch + 16);
regState.regs[SP] += 8;
} else {
DebugToRegState(&mach_DebugState, ®State);
}
PutReplyBytes(sizeof(regState), (Address) ®State);
SendReply();
}
case DBG_GET_DUMP_BOUNDS: {
Dbg_DumpBounds bounds;
extern unsigned int end;
bounds.pageSize = vm_PageSize;
bounds.stackSize = mach_KernStackSize;
bounds.kernelCodeStart = (unsigned int) mach_KernStart;
bounds.kernelCodeSize =
(unsigned int) (vmBootEnd - mach_KernStart);
bounds.kernelDataStart = VMMACH_VIRT_CACHED_START;
bounds.kernelDataSize = (unsigned int)
(vmMemEnd - VMMACH_VIRT_CACHED_START);
bounds.kernelStacksStart = (unsigned int)vmStackBaseAddr;
bounds.kernelStacksSize = (unsigned int)
(vmStackEndAddr - vmStackBaseAddr);
bounds.fileCacheStart = (unsigned int)vmBlockCacheBaseAddr;
bounds.fileCacheSize = (unsigned int) (vmBlockCacheEndAddr -
vmBlockCacheBaseAddr);
PutReplyBytes(sizeof(bounds), (char *)&bounds);
SendReply();
break;
}
case DBG_GET_VERSION_STRING: {
char *version;
version = SpriteVersion();
PutReplyBytes(strlen(version) + 1, version);
SendReply();
break;
}
case DBG_INST_READ:
case DBG_DATA_READ: {
Dbg_ReadMem readMem;
int status;
GetRequestBytes(sizeof(readMem), (Address) &readMem);
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("Addr=%x Numbytes=%d ",
readMem.address, readMem.numBytes);
}
if (Dbg_InRange(readMem.address, readMem.numBytes, FALSE)) {
status = 1;
PutReplyBytes(sizeof(status), (Address)&status);
PutReplyBytes(readMem.numBytes, (Address)readMem.address);
} else {
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("FAILURE ");
}
status = 0;
PutReplyBytes(sizeof(status), (Address)&status);
}
SendReply();
break;
}
case DBG_SET_PID: {
Proc_PID pid;
GetRequestBytes(sizeof(pid), (Address) &pid);
{
int dummy;
PutReplyBytes(4, (Address) &dummy);
SendReply();
}
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("pid %x ", pid);
}
if (pid == 0) {
procPtr = (Proc_ControlBlock *) NIL;
} else {
procPtr = Proc_GetPCB(pid);
if (procPtr == (Proc_ControlBlock *) NIL ||
procPtr == (Proc_ControlBlock *) 0 ||
procPtr->state == PROC_UNUSED ||
procPtr->state == PROC_DEAD ||
procPtr->state == PROC_NEW) {
Mach_MonPrintf("Can't backtrace stack for process %x\n",
pid);
procPtr = (Proc_ControlBlock *) NIL;
}
}
break;
}
case DBG_REBOOT: {
int stringLength;
char rebootString[100];
/*
* For a reboot command first read the size of the string and
* then the string itself.
*/
GetRequestBytes(sizeof(int), (Address)&stringLength);
if (stringLength != 0) {
GetRequestBytes(stringLength, (Address)rebootString);
}
rebootString[stringLength] = '\0';
{
int dummy;
PutReplyBytes(4, (Address) &dummy);
SendReply();
}
Mach_MonReboot(rebootString);
}
case DBG_INST_WRITE:
case DBG_DATA_WRITE: {
Dbg_WriteMem writeMem;
unsigned char ch;
/*
* For an instruction or a data write we first have to find out
* which address to write to and how many bytes to write. Next
* we have to make sure that the address is valid. If it is
* then we read the data and write it to the given address. If
* not we just report an error to kdbx.
*/
GetRequestBytes(2 * sizeof(int), (Address) &writeMem);
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("Addr=%x Numbytes=%d ",
writeMem.address, writeMem.numBytes);
}
if (Dbg_InRange((unsigned int) writeMem.address,
writeMem.numBytes, opcode == DBG_DATA_WRITE)) {
GetRequestBytes(writeMem.numBytes,
(Address) writeMem.address);
if (opcode == DBG_INST_WRITE) {
Mach_FlushCode((Address)writeMem.address,
writeMem.numBytes);
Mach_EmptyWriteBuffer();
}
ch = 1;
} else {
char buf[100];
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("FAILURE ");
}
GetRequestBytes(writeMem.numBytes, buf);
ch = 0;
}
PutReplyBytes(1, (char *) &ch);
SendReply();
break;
}
case DBG_WRITE_REG: {
Mach_RegState regState;
Dbg_WriteReg writeReg;
/*
* First find out which register is being written and
* then read the value.
*/
GetRequestBytes(sizeof(writeReg), (Address)&writeReg);
{
int dummy;
PutReplyBytes(4, (Address) &dummy);
SendReply();
}
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("register %d data %x ", writeReg.regNum,
writeReg.regVal);
}
if (procPtr != (Proc_ControlBlock *) NIL &&
procPtr->machStatePtr != (Mach_State *)NIL) {
((int *)
&procPtr->machStatePtr->switchRegState)[(writeReg.regNum)]
= writeReg.regVal;
} else {
DebugToRegState(&mach_DebugState, ®State);
((int *) ®State)[(writeReg.regNum)] = writeReg.regVal;
RegStateToDebug(®State, &mach_DebugState);
}
}
case DBG_DIVERT_SYSLOG:
GetRequestBytes(sizeof(Boolean), (Address)&syslogDiverted);
{
int dummy;
PutReplyBytes(4, (Address) &dummy);
SendReply();
}
break;
case DBG_BEGIN_CALL: {
/*
* We are beginning a call command. Fix up the stack
* so that we will be able to continue. We will put
* it back when we are done.
*/
int dummy;
if (dbgCanUseSyslog) {
dbg_UsingSyslog = TRUE;
}
PutReplyBytes(4, (Address) &dummy);
SendReply();
break;
}
case DBG_END_CALL: {
char *buffer;
int *firstIndexPtr;
int *lastIndexPtr;
int bufSize;
int length;
/*
* Dump the syslog buffer.
*/
Dev_SyslogReturnBuffer(&buffer, &firstIndexPtr,
&lastIndexPtr, &bufSize);
if (*firstIndexPtr == -1) {
length = 0;
PutReplyBytes(4, (Address) &length);
dbg_UsingSyslog = FALSE;
} else if (*firstIndexPtr <= *lastIndexPtr) {
length = *lastIndexPtr - *firstIndexPtr + 1;
if (length + 4 > PACKET_DATA_SIZE) {
length = PACKET_DATA_SIZE - 4;
}
PutReplyBytes(4, (Address) &length);
PutReplyBytes(length,
(Address)&buffer[*firstIndexPtr]);
*firstIndexPtr += length;
if (*firstIndexPtr > *lastIndexPtr) {
*firstIndexPtr = *lastIndexPtr = -1;
}
} else {
length = bufSize - *firstIndexPtr;
if (length + 4 > PACKET_DATA_SIZE) {
length = PACKET_DATA_SIZE - 4;
}
PutReplyBytes(4, (Address) &length);
PutReplyBytes(length,
(Address)buffer[*firstIndexPtr]);
*firstIndexPtr += length;
if (*firstIndexPtr == bufSize) {
*firstIndexPtr = 0;
}
}
SendReply();
break;
}
case DBG_CALL_FUNCTION: {
Dbg_CallFunc callFunc;
int returnVal;
static int argBuf[128];
GetRequestBytes(2 * sizeof(int), (Address) &callFunc);
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("Addr=%x Numbytes=%d ",
callFunc.address, callFunc.numBytes);
}
if ((callFunc.numBytes >= 0 && callFunc.numBytes < 128) &&
Dbg_InRange((unsigned int) callFunc.address,4,FALSE)) {
GetRequestBytes(callFunc.numBytes,(Address) argBuf);
returnVal = (* ((int (*)()) callFunc.address))(argBuf[0],
argBuf[1],argBuf[2],argBuf[3],argBuf[4],argBuf[5],argBuf[6],
argBuf[7],argBuf[8],argBuf[9]);
} else {
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("FAILURE ");
}
GetRequestBytes(callFunc.numBytes,(Address)argBuf);
returnVal = -1;
}
PutReplyBytes(4, (char *) &returnVal);
SendReply();
break;
}
case DBG_CONTINUE: {
/*
* The client wants to continue execution.
*/
int foo;
GetRequestBytes(sizeof(int),
(Address) &foo);
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("Continuing from pc %x ",debugStatePtr->excPC);
}
{
int dummy;
PutReplyBytes(4, (Address) &dummy);
SendReply();
}
dbg_BeingDebugged = TRUE;
done = TRUE;
break;
}
case DBG_SINGLESTEP: {
/*
* The client wants to single step.
*/
unsigned *pc;
int status;
int dummy;
GetRequestBytes(sizeof(int), (Address) &dummy);
pc = DbgGetDestPC((Address)(debugStatePtr->excPC));
if (dbgTraceLevel >= 1) {
Mach_MonPrintf("Single-step PC=%x\n", pc);
}
if (!Dbg_InRange((unsigned int)pc, 4, TRUE)) {
Mach_MonPrintf("Bad SSTEP PC\n");
status = 0;
} else {
sstepInst = *pc;
Mach_FlushCode((Address)pc, 4);
*pc = SSTEP_INST;
Mach_EmptyWriteBuffer();
dbg_BeingDebugged = TRUE;
done = TRUE;
status = 1;
}
PutReplyBytes(sizeof(status), (Address) &status);
SendReply();
break;
}
case DBG_DETACH:
/*
* The debugger has terminated and wants to let us go about our
* business.
*/
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("Detaching at pc %x ", debugStatePtr->excPC);
}
{
int dummy;
PutReplyBytes(4, (Address) &dummy);
SendReply();
}
dbg_BeingDebugged = FALSE;
done = TRUE;
printf("Sprite is now detached from the debugger\r\n");
break;
case DBG_UNKNOWN:
Mach_MonPrintf("debugger: unrecognized request\n");
break;
}
if (dbgTraceLevel >= 2) {
Mach_MonPrintf("\r\n");
}
if (!done) {
(void)ReadRequest(FALSE);
GetRequestBytes(4, (Address)&opcode);
}
}
#ifdef KDBX
there:
#endif
/*
* Don't force system log output to the console.
*/
if (!syslogDiverted) {
Dev_SyslogDebug(FALSE);
}
if (dbgTraceLevel >= 1) {
Mach_MonPrintf("Returning to %x: %x\n", debugStatePtr->excPC,
*(unsigned *)debugStatePtr->excPC);
}
mach_AtInterruptLevel = atInterruptLevel;
dbg_UsingNetwork = FALSE;
/*
* Flush out the old TLB mapping.
*/
VmMachWriteIndexedTLB(0, 0, 0);
dbg_InDebugger = FALSE;
return(debugStatePtr->excPC);
}
/*
*----------------------------------------------------------------------
*
* DebugToRegState --
*
* Converts a Mach_DebugState to Mach_RegState.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
DebugToRegState(debugPtr, regPtr)
Mach_DebugState *debugPtr;
Mach_RegState *regPtr;
{
regPtr->pc = (Address) debugPtr->excPC;
bcopy((char *) debugPtr->regs, (char *) regPtr->regs,
MACH_NUM_GPRS * sizeof(int));
bcopy((char *) debugPtr->fpRegs, (char *) regPtr->fpRegs,
MACH_NUM_FPRS * sizeof(int));
regPtr->fpStatusReg = debugPtr->fpCSR;
regPtr->mfhi = debugPtr->multHi;
regPtr->mflo = debugPtr->multLo;
}
/*
*----------------------------------------------------------------------
*
* RegStateToDebug --
*
* Converts a Mach_RegState to Mach_DebugState.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
RegStateToDebug(regPtr, debugPtr)
Mach_RegState *regPtr;
Mach_DebugState *debugPtr;
{
debugPtr->excPC = (unsigned) regPtr->pc;
bcopy((char *) regPtr->regs, (char *) debugPtr->regs,
MACH_NUM_GPRS * sizeof(int));
bcopy((char *) regPtr->fpRegs, (char *) debugPtr->fpRegs,
MACH_NUM_FPRS * sizeof(int));
debugPtr->fpCSR = regPtr->fpStatusReg;
debugPtr->multHi = regPtr->mfhi;
debugPtr->multLo = regPtr->mflo;
}